package cn.sgjk.train.business.service;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.EnumUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.sgjk.train.business.domain.*;
import cn.sgjk.train.business.enums.SeatTypeEnum;
import cn.sgjk.train.business.enums.TrainTypeEnum;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import cn.sgjk.train.common.resp.PageResp;
import cn.sgjk.train.common.util.SnowUtil;
import cn.sgjk.train.business.mapper.DailyTrainTicketMapper;
import cn.sgjk.train.business.req.DailyTrainTicketQueryReq;
import cn.sgjk.train.business.req.DailyTrainTicketSaveReq;
import cn.sgjk.train.business.resp.DailyTrainTicketQueryResp;
import com.github.pagehelper.util.StringUtil;
import jakarta.annotation.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class DailyTrainTicketService {

    private static final Logger LOG = LoggerFactory.getLogger(DailyTrainTicketService.class);

    @Resource
    private DailyTrainTicketMapper dailyTrainTicketMapper;

    @Autowired
    private TrainStationService trainStationService;

    @Autowired
    private DailyTrainSeatService dailyTrainSeatService;


//    @Autowired
//    private ConfirmOrderService confirmOrderService;

    @Autowired
    private RedisTemplate redisTemplate;

    public void save(DailyTrainTicketSaveReq req) {
        DateTime now = DateTime.now();
        DailyTrainTicket dailyTrainTicket = BeanUtil.copyProperties(req, DailyTrainTicket.class);
        if (ObjectUtil.isNull(dailyTrainTicket.getId())) {
            dailyTrainTicket.setId(SnowUtil.getSnowflakeNextId());
            dailyTrainTicket.setCreateTime(now);
            dailyTrainTicket.setUpdateTime(now);
            dailyTrainTicketMapper.insert(dailyTrainTicket);
        } else {
            dailyTrainTicket.setUpdateTime(now);
            dailyTrainTicketMapper.updateByPrimaryKey(dailyTrainTicket);
        }
    }

    //@CachePut("DailyTrainTicketService.queryList")
    public PageResp<DailyTrainTicketQueryResp> queryList2(DailyTrainTicketQueryReq req){
        return queryList(req);
    }
    //@Cacheable("DailyTrainTicketService.queryList")
    public PageResp<DailyTrainTicketQueryResp> queryList(DailyTrainTicketQueryReq req) {

        String TICKET_KEY = "DailyTrainTicketService.queryList";

        LOG.info("查询{}列车余票信息",req);
        DailyTrainTicketExample dailyTrainTicketExample = new DailyTrainTicketExample();
        dailyTrainTicketExample.setOrderByClause("id desc");
        DailyTrainTicketExample.Criteria criteria = dailyTrainTicketExample.createCriteria();



        if(ObjectUtil.isNotNull(req.getDate())) {
            criteria.andDateEqualTo(req.getDate());
            String date = DateUtil.format(req.getDate(), "yyyy-MM-dd");
            TICKET_KEY = TICKET_KEY +":" + date ;
        }

        if(StringUtil.isNotEmpty(req.getTrainCode())) {
            criteria.andTrainCodeEqualTo(req.getTrainCode());
            TICKET_KEY = TICKET_KEY +":" + req.getTrainCode();
        }

        if(StringUtil.isNotEmpty(req.getStart())) {
            criteria.andStartEqualTo(req.getStart());
            TICKET_KEY = TICKET_KEY  +":"+ req.getStart();
        }

        if(StringUtil.isNotEmpty(req.getEnd())) {
            criteria.andEndEqualTo(req.getEnd());
            TICKET_KEY = TICKET_KEY +":" + req.getEnd() ;
        }


        TICKET_KEY = TICKET_KEY + ":" + req.getPage();
        TICKET_KEY = TICKET_KEY + ":" + req.getSize();
        LOG.info("查询页码：{}", req.getPage());
        LOG.info("每页条数：{}", req.getSize());
        PageHelper.startPage(req.getPage(), req.getSize());

        if(redisTemplate.hasKey(TICKET_KEY)) {
            Object value = redisTemplate.opsForValue().get(TICKET_KEY);
            PageResp<DailyTrainTicketQueryResp> pageResp = new PageResp<>();
            BeanUtil.copyProperties(value,pageResp);
            LOG.info("从缓存里读取：{}",pageResp);
            return pageResp;
        }

        List<DailyTrainTicket> dailyTrainTicketList = dailyTrainTicketMapper.selectByExample(dailyTrainTicketExample);

        PageInfo<DailyTrainTicket> pageInfo = new PageInfo<>(dailyTrainTicketList);
        LOG.info("总行数：{}", pageInfo.getTotal());
        LOG.info("总页数：{}", pageInfo.getPages());

        List<DailyTrainTicketQueryResp> list = BeanUtil.copyToList(dailyTrainTicketList, DailyTrainTicketQueryResp.class);

        PageResp<DailyTrainTicketQueryResp> pageResp = new PageResp<>();
        pageResp.setTotal(pageInfo.getTotal());
        pageResp.setList(list);

        redisTemplate.opsForValue().set(TICKET_KEY,pageResp,60, TimeUnit.SECONDS);
        return pageResp;
    }

    public void delete(Long id) {
        dailyTrainTicketMapper.deleteByPrimaryKey(id);
    }


    public void genTicket(Date date, Train train) {

        //生成前进行判断是否生成过数据了  在循环体进行判断  高内聚低耦合  删除已有当天数据
        LOG.info("生成日期【{}】车次【{}】的车票信息开始", DateUtil.formatDate(date), train.getCode());

        DailyTrainTicketExample dailyTrainExample = new DailyTrainTicketExample();
        dailyTrainExample.createCriteria()
                .andDateEqualTo(date)
                .andTrainCodeEqualTo(train.getCode());
        dailyTrainTicketMapper.deleteByExample(dailyTrainExample);

        List<TrainStation> trainStations = trainStationService.selectAll(train.getCode());
        if(trainStations.isEmpty()) {
            LOG.info("没有该车站基础数据，生成余票车次信息结束");
            return;
        }
        /**
         * 火车 站与站之间应该为
         * AB
         * AC
         * AD
         * AE
         * BC
         * BD
         * BE
         * CD
         * CE
         */
        DailyTrainTicket dailyTrainTicket = new DailyTrainTicket();
        dailyTrainTicket.setDate(date);
        dailyTrainTicket.setTrainCode(train.getCode());




        for (int i = 0; i < trainStations.size(); i++) {


            // 得到出发站
            TrainStation start = trainStations.get(i);
            //公里/价格
            BigDecimal sumKM = BigDecimal.ZERO;
            dailyTrainTicket.setStart(start.getName());
            dailyTrainTicket.setStartPinyin(start.getNamePinyin());
            dailyTrainTicket.setStartTime(start.getOutTime());
            dailyTrainTicket.setStartIndex(start.getIndex());

            for (int j = (i + 1); j < trainStations.size(); j++) {
                dailyTrainTicket.setId(SnowUtil.getSnowflakeNextId());
                TrainStation end = trainStations.get(j);
                sumKM = sumKM.add(end.getKm());
                DateTime now = new DateTime();
                dailyTrainTicket.setEnd(end.getName());
                dailyTrainTicket.setEndPinyin(end.getNamePinyin());
                dailyTrainTicket.setEndTime(end.getInTime());
                dailyTrainTicket.setEndIndex(end.getIndex());

                //车次余票
                int ydz = dailyTrainSeatService.countSeat(date, train.getCode(), SeatTypeEnum.YDZ.getCode());
                int edz = dailyTrainSeatService.countSeat(date, train.getCode(), SeatTypeEnum.EDZ.getCode());
                int rw = dailyTrainSeatService.countSeat(date, train.getCode(), SeatTypeEnum.RW.getCode());
                int yw = dailyTrainSeatService.countSeat(date, train.getCode(), SeatTypeEnum.YW.getCode());

                // 票价 = 里程之和 * 座位单价 * 车次类型系数
                String trainType = train.getType();

                // 计算票价系数：TrainTypeEnum.priceRate
                BigDecimal priceRate = EnumUtil.getFieldBy(TrainTypeEnum::getPriceRate, TrainTypeEnum::getCode, trainType);

                BigDecimal ydzPrice = ydz == -1 ? BigDecimal.valueOf(0) : sumKM.multiply(SeatTypeEnum.YDZ.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                BigDecimal edzPrice = edz == -1 ? BigDecimal.valueOf(0) : sumKM.multiply(SeatTypeEnum.EDZ.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                BigDecimal rwPrice = rw == -1 ? BigDecimal.valueOf(0) : sumKM.multiply(SeatTypeEnum.RW.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                BigDecimal ywPrice = yw == -1 ? BigDecimal.valueOf(0) : sumKM.multiply(SeatTypeEnum.YW.getPrice()).multiply(priceRate).setScale(2, RoundingMode.HALF_UP);
                dailyTrainTicket.setYdz(ydz);
                dailyTrainTicket.setYdzPrice(ydzPrice);
                dailyTrainTicket.setEdz(edz);
                dailyTrainTicket.setEdzPrice(edzPrice);
                dailyTrainTicket.setRw(rw);
                dailyTrainTicket.setRwPrice(rwPrice);
                dailyTrainTicket.setYw(yw);
                dailyTrainTicket.setYwPrice(ywPrice);


                dailyTrainTicket.setCreateTime(now);
                dailyTrainTicket.setUpdateTime(now);
                dailyTrainTicketMapper.insert(dailyTrainTicket);

            }
        }


        // 从redis中移除余票key
        //confirmOrderService.removeCache(date,train.getCode(),train.getStart(),train.getEnd());

        LOG.info("生成日期【{}】车次【{}】的车票信息结束", DateUtil.formatDate(date), train.getCode());

    }

    //唯一键是否存在抽取成一个方法
    public DailyTrainTicket selectByUnique(Date date, String trainCode, String start, String end) {
        DailyTrainTicketExample dailyTrainTicketExample = new DailyTrainTicketExample();
        dailyTrainTicketExample.createCriteria()
                .andDateEqualTo(date)
                .andTrainCodeEqualTo(trainCode)
                .andStartEqualTo(start)
                .andEndEqualTo(end);
        List<DailyTrainTicket> tickets = dailyTrainTicketMapper.selectByExample(dailyTrainTicketExample);
        if(CollUtil.isNotEmpty(tickets)) {
            return tickets.get(0);
        }else {
            return null;
        }
    }


}
